
package jp.moisture.othello.player;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import javax.xml.crypto.KeySelector.Purpose;

import org.omg.CORBA.PUBLIC_MEMBER;

import jp.moisture.othello.board.Board;
import jp.moisture.othello.board.Board.State;
import jp.moisture.othello.board.Cell;
import jp.moisture.othello.board.Game;
import jp.moisture.othello.board.Stone;

public class DeepSearchPlayer extends Player {

    private static class Node {
        int mDepth;
        int mColor;
        int mPoint;
    }

    private static class CandidateCell implements Comparable<CandidateCell> {
        int mColor;
        Board mBoard;
        Cell mCell;
        State mState;

        public CandidateCell(int color, Board board, Cell cell, State state) {
            mColor = color;
            mBoard = board;
            mCell = cell;
            mState = state;
        }

        @Override
        public int compareTo(CandidateCell o) {
            return o.mState.getPoint(mColor) - mState.getPoint(mColor);
        }

        public boolean isWideMarginWon(int color) {
            return mState.isWideMarginWon(color);
        }

        @Override
        public String toString() {
            return Stone.toString(mColor) + "(" + mCell.getX() + ","
                    + mCell.getY() + "):" + mState.getPoint(mColor);
        }

        public boolean isWon() {
            return mState.isWon(mColor);
        }
    }

    private static final int MAX_DEPTH = 3;
    CountDownLatch mLatch;
    private boolean mNoGiveUp;
    private Board mMainBoard;
    private int mMind = MIND_NONE;
    private Node mNode;

    static int mCount;

    public DeepSearchPlayer(String name) {
        this(name, null, null);
    }

    public DeepSearchPlayer(String name, Board mainBoard, Node node) {
        super(name);
        mNode = node;
        mMainBoard = mainBoard;
    }

    @Override
    public final void setBoard(Board board) {
        super.setBoard(board);
        if (mMainBoard == null) {
            mMainBoard = board;
        }
    }

    public void setNoGiveUp(boolean noGiveUp) {
        mNoGiveUp = noGiveUp;
    }

    public Cell next() {
        if (mNode != null) {
            //			System.out.println(mNode.mDepth);
            if (mNode.mDepth < mBoard.getTurnCount()) {
                //			System.out.println(mBoard);
                return Cell.GIVE_UP;
            }
        }
        List<Cell> cells = mBoard.findPutableCells(mColor);
        if (cells.isEmpty()) {
            return null;
        } else if (cells.size() == 1) {
            return cells.get(0);
        }

        List<CandidateCell> advantageCells = new ArrayList<CandidateCell>();
        for (Cell cell : cells) {
            CandidateCell candidateCell = candidate(cell);
            if (candidateCell != null) {
                if (candidateCell.isWideMarginWon(mColor)) {
                    mMind = MIND_WINNER;
                    advantageCells.add(candidateCell);
                } else if (!candidateCell
                        .isWideMarginWon(mColor == Stone.BLACK ? Stone.WHITE
                                : Stone.BLACK)) {
                    advantageCells.add(candidateCell);
                }
            }
        }
        if (advantageCells.isEmpty()) {
            // if (mNoGiveUp) {
            // return cells.get(0);
            // } else {
            mMind = MIND_LOOSER;
            return Cell.GIVE_UP;
            // }
        }
        Collections.sort(advantageCells);
        if (mMind == MIND_WINNER) {
            return advantageCells.get(0).mCell;
        }
        int basePoint = advantageCells.get(0).mState.getPoint(mColor);
        List<CandidateCell> pruningCells = new ArrayList<CandidateCell>();
        for (CandidateCell cell : advantageCells) {
            // System.out.println(basePoint - cell.mState.getPoint(mColor));
            if (basePoint - cell.mState.getPoint(mColor) < 60) {
                pruningCells.add(cell);
            }
        }
        if (pruningCells.size() > 3) {
            pruningCells = pruningCells.subList(0, 3);
        }
        // System.out.println(advantageCells.size() + " -> " +
        // pruningCells.size());
        // System.out.println(pruningCells.size());

        Node node = null;
        if (mNode == null) {
            node = new Node();
            node.mColor = mColor;
            node.mDepth = mMainBoard.getTurnCount() + 9;
        } else {
            node = mNode;
        }
        ArrayList<CandidateCell> nextCells = new ArrayList<CandidateCell>();
        for (CandidateCell cell : pruningCells) {
            CandidateCell candidateCell = search(cell, node);
            if (candidateCell != null) {
                if (candidateCell.isWon()) {
                    mMind = MIND_WINNER;
                    return candidateCell.mCell;
                }
                nextCells.add(candidateCell);
                // return candidateCell.mCell;
            }
        }
        if (nextCells.isEmpty()) {
            mMind = MIND_LOOSER;
            return advantageCells.get(0).mCell;
        }
        return nextCells.get(0).mCell;
    }

    private final CandidateCell candidate(Cell cell) {
        // Board board = mBoard.clone();
        Board board = new Board(mBoard);
        board.setStone(cell.getX(), cell.getY(), mColor);
        State state = board.getState();
        // if (state.getPoint(mColor) >= 0) {
        return new CandidateCell(mColor, board, cell, state);
        // } else {
        // return null;
        // }
    }

    private final CandidateCell search(CandidateCell candidateCell, Node node) {
        // player1.setNoGiveUp(true);
        // player2.setNoGiveUp(true);

        Board board = candidateCell.mBoard;
        Cell cell = candidateCell.mCell;
        // int depth = (int) Math.ceil(MAX_DEPTH * ((double)
        // mMainBoard.getStoneCount() / (mMainBoard.getSize() *
        // mMainBoard.getSize())));
        int depth;
        int emptys = mMainBoard.getEmptyCellCount();
        // if (emptys <= 24) {
        // depth = 100;
        // } else if (emptys <= 32) {
        // depth = 7;
        // } else if (emptys <= 40) {
        // depth = 5;
        // } else if (emptys <= 44) {
        // depth = 4;
        // } else if (emptys <= 48) {
        // depth = 3;
        // } else {
        // depth = 3;
        // }
        depth = 11;
        depth = 3;
        if (emptys <= 19) {
            depth = 19;
        } else if (emptys <= 21) {
            depth = 21;
        } else if (emptys <= 23) {
            depth = 23;
        } else if (emptys <= 29) {
            depth = 13;
        }

        DeepSearchPlayer player1;
        DeepSearchPlayer player2;
        if (board.getTurnCount() % 2 == 0) {
            player1 = new DeepSearchPlayer("one", mMainBoard, node);
            player2 = new DeepSearchPlayer("two", mMainBoard, node);
        } else {
            player1 = new DeepSearchPlayer("one", mMainBoard, node);
            player2 = new DeepSearchPlayer("two", mMainBoard, node);
        }
        player1.setNoGiveUp(true);
        player2.setNoGiveUp(true);

        // System.out.println("main board : " + mMainBoard.getEmptyCellCount());
        // if (mMainBoard.getEmptyCellCount() < 24) {
        // player1.setNoGiveUp(true);
        // player2.setNoGiveUp(true);
        // }

        VirtualGame game = new VirtualGame(board.getSize(), player1, player2,
                board, mMainBoard.getTurnCount() + depth);
        game.setListener(game);
        game.start();
        State state = game.getState();
        // return new CandidateCell(mColor, board, cell, state);
        if (player1.hearMind() != MIND_LOOSER && !state.isLoose(mColor)) {
            return new CandidateCell(mColor, board, cell, state);
        } else {
            // System.out.println("looser! " + player1.hearMind() + " : " +
            // state.isLoose(mColor));
            return null;
        }
    }

    @Override
    public int hearMind() {
        return mMind;
    }
}
